
#include "ssp.h"
#include "micco.h"
//#include "misc.h"
#include "types.h"

#define I2S_SSP_PORT	3
#define PCM_SSP_PORT	4

/*
 * Set the SSP ports SYSCLK.
 */
#define SSCR0_SCR	(0x000fff00)	/* Serial Clock Rate (mask) */
#define SSCR0_SerClkDiv(x) (((x) - 1) << 8)	/* Divisor [1..4096] */
#define SSCR0_EDSS	(1 << 20)	/* Extended data size select */
#define SSCR0_NCS	(1 << 21)	/* Network clock select */
#define SSCR0_RIM	(1 << 22)	/* Receive FIFO overrrun interrupt mask */
#define SSCR0_TUM	(1 << 23)	/* Transmit FIFO underrun interrupt mask */
#define SSCR0_FRDC	(0x07000000)	/* Frame rate divider control (mask) */
#define SSCR0_SlotsPerFrm(x) ((x) - 1)	/* Time slots per frame [1..8] */
#define SSCR0_ADC	(1 << 30)	/* Audio clock select */
#define SSCR0_MOD	(1 << 31)	/* Mode (normal or network) */
#define SSCR0_ECS	(1 << 6)	/* External clock select */-----------------------

#define SSCR0_ACS	(1 << 30) /* Audio Clock Select */
#define SSACD_SCDB	(1 << 3) /* SSPSYSCLK Divider Bypass */
#define SSACD_SCDX8	(1 << 7) /* SSPSYSCLK Divide by 8 */

/* SSP clock sources */
#define PXA3XX_SSP_CLK_PLL	0
#define PXA3XX_SSP_CLK_EXT	1
#define PXA3XX_SSP_CLK_NET	2
#define PXA3XX_SSP_CLK_AUDIO	3

/* SSP audio dividers */
#define PXA3XX_SSP_AUDIO_DIV_ACDS		0
#define PXA3XX_SSP_AUDIO_DIV_SCDB		1
#define PXA3XX_SSP_DIV_SCR			2

/*
 * SSP audio private data
 */
struct ssp_priv {
	unsigned int sysclk;
	int dai_fmt;
};

static struct ssp_priv ssp_clk[4];
static int cken[4] = {CKEN_SSP1, CKEN_SSP2, CKEN_SSP3, CKEN_SSP4};

 int pxa3xx_ssp_set_dai_sysclk(int id, int clk_id, unsigned int freq, int dir)
{
	int port = id ;
//	unsigned int loc = ~(SSCR0_ECS |  SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
	unsigned int loc = ~( (1<<6) |(1<<21) | (1<<31) |(1<<30));
	unsigned int  sscr0 = SSCR0_P(port+1) & loc;

	switch (clk_id) {
	case PXA3XX_SSP_CLK_PLL:
		ssp_clk[id].sysclk = 13000000;
		break;
	case PXA3XX_SSP_CLK_EXT:
		ssp_clk[id].sysclk = freq;
		sscr0 |= (1<<6);//SSCR0_ECS;
		break;
	case PXA3XX_SSP_CLK_NET:
		ssp_clk[id].sysclk = freq;
		sscr0 |= (SSCR0_NCS | SSCR0_MOD);
		break;
	case PXA3XX_SSP_CLK_AUDIO:
		ssp_clk[id].sysclk = 0;
		SSCR0_P(port+1) |= SSCR0_SerClkDiv(1);
		sscr0 |= SSCR0_ACS;
		break;
	default:
		return -1;
	}

	/* the SSP CKEN clock must be disabled when changing SSP clock mode */
	pxa_set_cken(cken[id], 0);
	SSCR0_P(port+1) |= sscr0;
	pxa_set_cken(cken[id], 1);
	return 0;
}

#define __raw_writel(v,a)	(*(volatile unsigned int  *)(a) = (v))
#define __raw_readl(a)		(*(volatile unsigned int   *)(a))
static void enable_oscc_pout(void)
{
	unsigned long val;
	val = __raw_readl((void*)&OSCC);
	val |= OSCC_PEN;
	__raw_writel(val, (void*)&OSCC);

	return;
}

 int littleton_micco_hifi_startup()
{
	enable_oscc_pout();
	return 0;
}

int micco_hifi_prepare()
{
	u8 val = 0;

	if ( 0) //substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
	{
		micco_codec_read( MICCO_I2S_CONTROL, &val);
		switch (48000) {
			case 8000:
				val &= 0xF0;
				break;
			case 11025:
				val &= 0xF0;
				val |= 0x01;
				break;
			case 12000:
				val &= 0xF0;
				val |= 0x02;
				break;
			case 16000:
				val &= 0xF0;
				val |= 0x03;
				break;
			case 22050:
				val &= 0xF0;
				val |= 0x04;
				break;
			case 24000:
				val &= 0xF0;
				val |= 0x05;
				break;
			case 32000:
				val &= 0xF0;
				val |= 0x06;
				break;
			case 44100:
				val &= 0xF0;
				val |= 0x07;
				break;
			case 48000:
				val &= 0xF0;
				val |= 0x0F;
				break;
			default:
				return -1;
		}
		val &= 0x0F;
		val |= 0x10;
		micco_codec_write(MICCO_I2S_CONTROL, val);


	} else {
		printf("Micco HIFI does not support capture!\n");
		return -1;
	}
	return 0;
}



 int littleton_micco_hifi_prepare()
{
	unsigned long sscr0, sscr1, sspsp, sstsa;
	unsigned long ssacd, ssacdd, ssrsa;
#if 0
	pxa3xx_ssp_set_dai_sysclk(2, PXA3XX_SSP_CLK_EXT, 13000000, 0);
#endif

	/* Because the internal 13M clock will be 10M in D0CS,
	 * we route SSP_CLK to GPIO126(EXT_CLK) and let SSP select
	 * NETWORK CLK as CLK source.
	 * This workaround need an ECO on Littleton mainboard.
	 */
	sscr0 = 0xA1E0003F;
//	sscr0 = 0x81E0003F;//diable the transmit dma
//	sscr1 = 0x00701DC0;
	sscr1 = 0x00401D00;//diable the dma

	sspsp = 0x40200004;
	sstsa = 0x00000003;
	ssrsa = 0x00000003;
	ssacd = 0x60;
	ssacdd= 0x00000040;
	sscr0 |= 0x00000300;


//asm
sscr0 = 0x4010003F;
sscr1 = 0x00A00000;
sspsp = 0x02200400;
ssacd = 0x60;
ssacdd = 0x06590040;
//

	SSCR0_P(I2S_SSP_PORT) = sscr0;
	SSCR1_P(I2S_SSP_PORT) = sscr1;
	SSPSP_P(I2S_SSP_PORT) = sspsp;
//	SSTSA_P(I2S_SSP_PORT) = sstsa;
//	SSRSA_P(I2S_SSP_PORT) = ssrsa;
	SSACD_P(I2S_SSP_PORT) = ssacd;
	SSACDD_P(I2S_SSP_PORT) = ssacdd;

	return 0;
}

/*
 * Logic for a Micco as connected on a littleton Device
 */
 int littleton_micco_init()
{
	micco_codec_write(MICCO_I2S_CONTROL, 0x10);
	return 0;
}


